
在設計函式與呼叫函式前,或許得認識到一些限制,這些限制有可能造成需要使用不同的設計方式或呼叫方式。就來談一下一些在JavaScript語言裡的一些限制吧!
JavaScript裡關於「整數」是有範圍限制在的,按照規範這個值的範圍是(±2**53)內,也就是-9007199254740991~9007199254740992。這個值你可以透過Number.MIN_SAFE_INTEGER和Number.MAX_SAFE_INTEGER取得。
在ES11後多加了一個基本類別BigInt,儘管這個類型的使用方式和Number並不相容^1。但是在過去寫過的7天搞懂js進階議題中曾經使用過。如果你有需要超過-9007199254740991~9007199254740992範圍的整數,可以考慮使用BigInt。
Array會需要留意:屬性.length的最大值爲2**32-1也就是4294967295。
這意味著以下一些操作是會出問題的
var arr = Array(4294967296); // 超出最大範圍
{
let arr = Array(4294967295);
arr.push(0); // 超出最大範圍
}
此外,-1的索引值並不是像Python會得到最後一個元素^2。實際上經過以下操作:
var arr = [1,2,3,4];
arr[-1] = 5;
console.log(arr);
最後arr的結果應該會像是:
[-1: 5, 1, 2, 3, 4]
另外.length也不會算上-1的索引值。
console.log(arr.length); // 4
實際上存取和賦值和Object類似,可以使用任何字串存取:
console.log(arr["0"]); // 1
console.log(arr["-1"]); // 5
注意的是0.1 + 0.2和0.3是不同的:
arr[0.1+0.2] = 0.3;
console.log(arr[0.3]); // undefined
儘管Array的屬性.length的最大值爲4294967295,但是Array遠可以儲存超過這個數量的物件。
經過嘗試,
Array取值同樣接受類型BigInt,這意味者你可以透過BigInt存取或賦值超過整數安全範圍的值。但是屬性.length仍不會超過最大值。
arguments一般函式會有一個隱藏變數arguments保留了所有輸入參數(但是箭頭函式不會有)。
function fn() {
console.log(arguments);
}
fn(1, 2, 3, 4); // Arguments(4)[1, 2, 3, 4]
這個變數雖然有Array的特性,但是卻不是Array
function fn() {
console.log(arguments instanceof Array);
}
fn(1, 2, 3, 4); // false
相對來說參數蒐集(剩餘參數)就是Array類型
function fn(...args) {
console.log(args instanceof Array);
}
fn(1, 2, 3, 4); // true
其實經過以上訊息,就可以猜想到 函式參數的有最大數量的限制 。這個數值從語言層面來看可能是9007199254740992或是4294967295。但其實通常遠小於這個數值,我在Edge瀏覽器特定情況下最大可以傳遞125681個參數:
var arr = Array(125681);
function fn(...args){
console.log(args[0]);
}
fn(...arr)
fn(1, ...arr); // 超出限制
實際上這並不是一個常數值。
function fn2(...args){
fn(...args);
}
fn2(...arr); // 超出限制

還記得提到過的Call Stack嗎?

Call Stack通常是有最大容量限制的。
這意味著以下函式最終會出現問題:
function recursive(){
return recursive();
}
recursive(); // 最終會發生錯誤

function fn(...args){
console.log(args[0]);
}
function fn2(...args){
fn(...args);
}
fn2(1, 2, 3);
實際上參數傳遞也可能會佔用Call Stack的空間。以上面程式碼片段來說,這個過程更像是:
fn2(1, 2, 3)
| Call Stack |
| ---------- |
| |
| |
| |
| |
| Num : 3 |
| Num : 2 |
| Num : 1 |
| Func: fn2 |
+------------+
fn(1, 2, 3)
| Call Stack |
| ---------- |
| Num : 3 |
| Num : 2 |
| Num : 1 |
| Func: fn |
| Num : 3 |
| Num : 2 |
| Num : 1 |
| Func: fn2 |
+------------+
| Call Stack |
| ---------- |
| |
| |
| |
| undefined |
| Num : 3 |
| Num : 2 |
| Num : 1 |
| Func: fn2 |
+------------+
| Call Stack |
| ---------- |
| |
| |
| |
| |
| |
| |
| |
| undefined |
+------------+

當你在設計或使用函式時,需要考慮應該使用 剩餘參數 還是接受一個 陣列物件 。視情況還有可能使用Array.prototype.reduce()來處理一些問題。這些語言以及實現層面的限制存在,也就需要了解Function.prototype.call()和Function.prototype.apply()。
本文同時發表於我的隨筆